static private var rxNormalMode:RegExp = /^\[|(\n|\r)\[/g;
static private var rxInlineComment:RegExp = /\s.#/g;

static public function INI( $data:String ):*{
	var line:String, lines:Array, lineLength:uint, group:String, mode:String, result:*, isCommentMode:Boolean,
		tmpGroup:String, key:String, value:String, type:String, subtype:String, mapping:Array,
		valArr:Array, valTarget:Array, prevTarget:Array, valData:*, valPrev:int,
		objResult:Object,objArr:Array,objName:String,objVal:String,obj:int,obi:int,
		i:int, j:int, k:int, l:int, m:int, n:int, modeIdx:int;
	
	mapping = [];
	result = {};
	$data = trim( $data );
	if( $data.indexOf( '\n' ) > -1 ){
		lines = $data.split( '\n' );
	}else{
		lines = $data.split( '\r' );
	}
	
	lineLength = lines.length;
	
	if( $data.search( rxNormalMode ) === -1 ){
		group = '@GLOBAL';
		result[group] = [];
		mode = 'array';
	}
	isCommentMode = false;
	for( i = 0 ; i < lineLength ; ++i ){
		line = trim( lines[i] );
		while( line.substr( -2 ) === '@@' ){
			line = trim( line.substring( 0, line.lastIndexOf( '@@' ) ) );
			line += ' ' + trim( lines[++i] );
		}
		if( isCommentMode ){
			if( line.substr( -2 ) === '*/' ){
				isCommentMode = false;
				continue;
			}
		}
		
		switch( line.charAt(0) ){
		case'':case'#':break;
		case'/':
			if( line.charAt(1) === '*' ){
				isCommentMode = true;
			}
			break;
		case'[':
			tmpGroup = line.substring( 1, line.indexOf( ']' ) );
			if( tmpGroup ){
				if( tmpGroup.indexOf(':') === -1 ){
					group=tmpGroup;
					if( group.substr( 0, 2 ) === '@@' ){
						result[group]=[];
						mode = 'array';
					}else{
						result[group]={};
						mode = 'object';
					}
				}else{
					group = tmpGroup.split(':')[0];
					mode = tmpGroup.split(':')[1].toLowerCase();
					switch(mode){
					case'array': result[group]=[]; break;
					case'script': result[group]=[]; break;
					default: SELF.error( mode + ' - 알 수 없는 그룹타입입니다' ); 
					}
				}
			}
			break;
		default:
			if( result[group] === undefined ){
				SELF.error( group + ' - 그룹이 정상적으로 생성되지 않았습니다.' );
			}
			if( line.search( rxInlineComment ) > -1 ){
				line = line.substr( 0, line.search( rxInlineComment ) );
			}
			if( mode === 'object' || mode === 'obj' ){
				modeIdx = line.indexOf( '=' );
				if( modeIdx === -1 ){
					mode = 'array';
				}
			}
			switch(mode){
			case'object':case'obj':
				key = trim( line.substring(0 , modeIdx ) );
				if( key ){
					if( key.charAt(0) === '(' ){
						type = key.substring( 1, key.indexOf( ')' ) );
						key = trim( key.substr( key.indexOf( ')' ) + 1 ) );
					}else{
						type='str';
					}
					value = line.substr( modeIdx + 1 );
				}else{
					SELF.error( '키가 제대로 지정되지 않았습니다. - '+ i.toString() + '번째 줄\n' + line );
				}
				break;
			case'array':case'arr':
				key = result[group].length.toString();
				if( line.charAt(0) === '(' ){
					type = line.substring( 1, line.indexOf( ')' ) );
					value = line.substr( line.indexOf( ')' ) + 1 );
				}else{
					type = 'str';
					value = line;
				}
				break;
			case'script':
				key = result[group].length.toString();
				type = 'txt';
				value = line;
				break;
			default:
				SELF.error( mode + ' - 알 수 없는 그룹타입입니다' ); 
			}
			type = type.toLowerCase();
			switch( type ){
			case'boolean': type = 'bool'; break;
			case'object': type = 'obj'; break;
			case'text': type = 'txt'; break;
			case'array': type = 'arr'; break;
			case'number': type = 'num'; break;
			case'expression': type = 'ex'; break;
			case'string': type = 'str'; break;
			}
			
			if( type === 'txt' || type ==='obj' || value.indexOf( ',' ) === -1 ){
				result[group][key] = value;
				switch(type){
				case'obj':
//					result[group][key] = valTarget = {};
//					prevTarget = [];
//					valArr = value.split(",");
//					for( k = 0, l = valArr.length ; k < l ; ++k ){
//						valPrev = 0;
//						valKey = '';
//						valData = trim( valArr[k] );
//						if( valData ){
//							if( valData.indexOf(':') > -1 ){
//								valKey = valData.substring( 0, valData.indexOf(':') );
//								valData = valData.substr( valData.indexOf(':') + 1 );
//							}
//							if( valData ){
//								if( valData.charAt(0) === '[' ){
//									valData = valData.substr( 1 );
//									valTarget[valTarget.length] = [];
//									prevTarget[prevTarget.length] = valTarget;
//									valTarget = valTarget[valTarget.length - 1]; 
//								}else if( valData.charAt(0) === '{' ){
//									valData = valData.substr( 1 );
//									valTarget[valTarget.length] = [];
//									prevTarget[prevTarget.length] = valTarget;
//									valTarget = valTarget[valTarget.length - 1];
//								}else if( valData.substr(-1) === ']' ){
//									while( valData.substr(-1) === ']' ){
//										valData = trim( valData.substr( 0, valData.length - 1 ) );
//										++valPrev;
//									}
//								}
//							}
//							
//							
//						}
//							if( valData.charAt(0) === '[' ){
//								valData = valData.substr( 1 );
//								valTarget[valTarget.length] = [];
//								prevTarget[prevTarget.length] = valTarget;
//								valTarget = valTarget[valTarget.length - 1]; 
//							}else if( valData.substr(-1) === ']' ){
//								while( valData.substr(-1) === ']' ){
//									valData = trim( valData.substr( 0, valData.length - 1 ) );
//									++valPrev;
//								}
//							}
//							if( valData ){
//						
//					}
					objResult = {};
					objArr = value.split(':');
					objName = trim( objArr[0] );
					if( objName.charAt(0) === '(' ){
						subtype = objName.substring( 1, objName.indexOf( ')' ) );
						objName = trim( objName.substr( objName.indexOf( ')' ) + 1 ) );
					}else{
						subtype = 'str';
					}
					for( obi = 1, obj = objArr.length ; obi < obj ; ++obi ){
						if( objArr[obi].charAt(0) === '[' ){
							objResult[objName] = objArr[obi].substring( 1, objArr[obi].indexOf( ']' ) ).split( ',' );
							if( obi < obj - 1 ){
								objName = objArr[obi].substring( objArr[obi].indexOf( ']' ) + 2 );
							}
						}else if( obi < obj -1 ){
							objResult[objName] = setINItype( subtype, objArr[obi].substring( 0, objArr[obi].lastIndexOf( ',' ) ), result[group] );
							
							objName = trim( objArr[obi].substring( objArr[obi].lastIndexOf( ',' ) + 1 ) );
							if( objName.charAt(0) === '(' ){
								subtype = objName.substring( 1, objName.indexOf( ')' ) );
								objName = trim( objName.substr( objName.indexOf( ')' ) + 1 ) );
							}else{
								subtype = 'str';
							}
						}else{
							objResult[objName] = setINItype( subtype, objArr[obi], result[group] );
						}
					}
					result[group][key] = objResult;
					break;
				default:
					result[group][key] = setINItype( type, result[group][key], result[group] );
					if( result[group][key] is String && result[group][key].substr( 0, 4 ) === '@MAP' ){
						mapping[mapping.length] = [group, key, result[group][key].substr( 4 )];
					}
					break;
				}
			}else{
				result[group][key] = valTarget = [];
				prevTarget = [];
				if( value.indexOf( '[' ) > -1 ){
					for( k = 0, l = value.length, m = 0, n = 0 ; k < l ; ++k ){
						if( value.charAt( k ) === '[' ){
							++m;
						}else if( value.charAt( k ) === ']' ){
							++n
						}
					}
					if( m === n ){}else{
						SELF.error( '대괄호 짝이 맞지 않습니다. - ' + group + '항목 ' + key + '번째 줄' );
					}
				}
				valArr = value.split(",");
				for( k = 0, l = valArr.length ; k < l ; ++k ){
					valPrev = 0;
					valData = trim( valArr[k] );
					subtype = '';
					if( valData ){
						if( valData.charAt(0) === '[' ){
							while( valData.charAt(0) === '[' ){
								valData = valData.substr( 1 );
								valTarget[valTarget.length] = [];
								prevTarget[prevTarget.length] = valTarget;
								valTarget = valTarget[valTarget.length - 1]; 
							}
						}
						if( valData ){
							if( valData.substr(-1) === ']' ){
								while( valData.substr(-1) === ']' ){
									valData = trim( valData.substr( 0, valData.length - 1 ) );
									++valPrev;
								}
							}
							if( valData ){
								if( valData.charAt(0) === '(' ){
									subtype = valData.substring( 1, valData.indexOf(')') );
									valData = trim( valData.substr( valData.indexOf(')') + 1 ) );
								}
							}
						}
					}
					if( subtype ){
						valData = setINItype( subtype, valData, result[group] );
					}else{
						valData = setINItype( type, valData, result[group] );
					}
					valTarget[valTarget.length] = valData;
					for( m = 0 ; m < valPrev ; ++m ){ 
						if( prevTarget.length ){
							valTarget = prevTarget.pop(); 
						}else{
							valTarget = result[group][key];
						}
					}
				}
			}
			break;
		}
	}
	if( group === '@GLOBAL' ){
		result = result['@GLOBAL'];
	}
	for( i = 0, j = mapping.length ; i < j ; ++i ){
		result[mapping[i][0]][mapping[i][1]] = result[mapping[i][2]];
	}
	return result;
}
static private function setINItype( $type:String, $value:String, $variables:Object ):*{
	$value = trim( $value );
	switch( $type ){
	case'int': return int( $value );
	case'uint': return uint( $value );
	case'num': return Number( $value );
	case'bool': return $value === 'true' ? true : false;
	case'ex':return EXPRESSION( $value, $variables );
	case'str':
		if( $value === 'true' ){
			return true;
		}else if( $value === 'false' ){
			return false;
		}else if( $value.charAt(0) === '[' ){
			return '@MAP' + $value.substring( 1, $value.indexOf( ']', 1 ) );
		}else{
			switch( $value.substr(0,2) ){
			case'0x': return uint( $value.substr( 2 ) );
			case'0n': return Number( $value.substr( 2 ) );
			}
			return $value;
		}
	case'txt':
		return $value;
	case'obj':
		if( $value.charAt(0) === "'" ){
			return $value.substring( 1, $value.length - 1 ); 
		}else{
			return Number($value);
		}
	default:
		SELF.error( $type + ' - 알 수 없는 형입니다' );
	}
}